/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : SPI Flash Example
 ******************************************************************************
 * @attention
 *
 * SPI读写W25Qxx Flash示例
 * 演示Flash的擦除、写入、读取和数据验证
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#include "./BSP/SPI/bsp_spi.h"
#include "./Devices/W25Qxx/bsp_w25qxx.h"
#include "./BSP/USART/bsp_usart.h"
#include <stdio.h>
#include <string.h>

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void Flash_Test(void);

/**
 * @brief  主函数
 */
int main(void)
{
    uint16_t manufacturer_id, device_id;
    
    /* HAL库初始化 */
    HAL_Init();
    
    /* 系统时钟配置 */
    SystemClock_Config();
    
    /* 初始化串口（用于printf调试） */
    usart_init(115200);
    
    printf("\r\n========================================\r\n");
    printf("  W25Qxx SPI Flash 测试程序\r\n");
    printf("========================================\r\n\r\n");
    
    /* 初始化SPI */
    spi_init();
    
    /* 初始化Flash */
    w25qxx_init();
    
    /* 读取Flash ID */
    if (w25qxx_read_id(&manufacturer_id, &device_id) == W25QXX_OK)
    {
        printf("Flash ID: MFR=0x%04X, DEV=0x%04X\r\n", manufacturer_id, device_id);
        
        if (manufacturer_id == 0xEF)
        {
            printf("✅ Flash芯片识别成功！\r\n\r\n");
        }
        else
        {
            printf("❌ Flash芯片识别失败！\r\n");
            while (1);
        }
    }
    
    /* Flash测试 */
    Flash_Test();
    
    /* 主循环 */
    while (1)
    {
        HAL_Delay(1000);
    }
}

/**
 * @brief  Flash测试函数
 */
void Flash_Test(void)
{
    uint8_t write_buf[256];
    uint8_t read_buf[256];
    uint32_t test_addr = 0x000000;
    
    /* 准备测试数据 */
    for (int i = 0; i < 256; i++)
    {
        write_buf[i] = i;
    }
    
    printf("【测试1】扇区擦除测试\r\n");
    printf("擦除地址: 0x%06lX\r\n", test_addr);
    
    if (w25qxx_erase_sector(test_addr) == W25QXX_OK)
    {
        printf("✅ 扇区擦除成功！\r\n\r\n");
    }
    else
    {
        printf("❌ 扇区擦除失败！\r\n");
        return;
    }
    
    printf("【测试2】数据写入测试\r\n");
    printf("写入地址: 0x%06lX\r\n", test_addr);
    printf("写入长度: 256 字节\r\n");
    
    if (w25qxx_write(test_addr, write_buf, 256) == W25QXX_OK)
    {
        printf("✅ 数据写入成功！\r\n\r\n");
    }
    else
    {
        printf("❌ 数据写入失败！\r\n");
        return;
    }
    
    printf("【测试3】数据读取测试\r\n");
    
    if (w25qxx_read(test_addr, read_buf, 256) == W25QXX_OK)
    {
        printf("✅ 数据读取成功！\r\n\r\n");
    }
    else
    {
        printf("❌ 数据读取失败！\r\n");
        return;
    }
    
    printf("【测试4】数据校验测试\r\n");
    
    if (memcmp(write_buf, read_buf, 256) == 0)
    {
        printf("✅ 数据校验通过！\r\n\r\n");
    }
    else
    {
        printf("❌ 数据校验失败！\r\n");
        
        /* 打印前16字节对比 */
        printf("写入数据: ");
        for (int i = 0; i < 16; i++) printf("%02X ", write_buf[i]);
        printf("\r\n读取数据: ");
        for (int i = 0; i < 16; i++) printf("%02X ", read_buf[i]);
        printf("\r\n");
        
        return;
    }
    
    /* 字符串测试 */
    printf("【测试5】字符串写入测试\r\n");
    
    const char *test_str = "Hello, W25Qxx Flash!";
    uint32_t str_addr = 0x001000;
    
    w25qxx_erase_sector(str_addr);
    w25qxx_write(str_addr, (const uint8_t *)test_str, strlen(test_str) + 1);
    
    memset(read_buf, 0, sizeof(read_buf));
    w25qxx_read(str_addr, read_buf, strlen(test_str) + 1);
    
    printf("写入字符串: %s\r\n", test_str);
    printf("读取字符串: %s\r\n", (char *)read_buf);
    
    if (strcmp(test_str, (char *)read_buf) == 0)
    {
        printf("✅ 字符串测试通过！\r\n\r\n");
    }
    else
    {
        printf("❌ 字符串测试失败！\r\n");
    }
    
    printf("========================================\r\n");
    printf("  所有测试完成！\r\n");
    printf("========================================\r\n");
}

/**
 * @brief  系统时钟配置
 */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);
    
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
}

int fputc(int ch, FILE *f)
{
    usart_send_byte((uint8_t)ch);
    return ch;
}
